home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
FishMarket 1.0
/
FishMarket v1.0.iso
/
fishies
/
526-550
/
disk_528
/
keymenu
/
src.lzh
/
KeyMenu-Handler.asm
next >
Wrap
Assembly Source File
|
1991-08-03
|
87KB
|
1,353 lines
*******************************************************************************
*
* KeyMenu-Handler.asm V1.05 21 Apr 1991
*
*
*
* This program is loaded by 'KeyMenu' and stays resident in the
* system until the user runs KeyMenu with the 'QUIT' option.
*
*
*
* Modification History:
*
* Date By Modification
* -------- -------------------- --------------------------------------
* 09/09/89 Ken Lowther Initial release, V1.01
*
* 09/13/89 Ken Lowther V1.02 - added qualifier keys to move
* mouse pointer to first/last item.
*
* 09/24/89 Ken Lowther V1.02 - corrected positioning of mouse
* pointer on menus. The pointer was being
* positioned 1 pixel to the left. This
* really only mattered when the menu is
* 1 pixel wide.
*
* 09/30/89 Ken Lowther V1.02 - Keymenu no longer creates a
* process for this module. Changed 'main'
* to set the DOS return code and return
* in case this module gets 'execute'ed.
*
* 10/03/89 Ken Lowther V1.02 - Changed to ignore the 1st
* occurance of a 'repeated' key. This
* is to fix a problem that occurs when
* there are more than 2 bitplanes in the
* screen.
*
* 03/02/91 Ken Lowther V1.03 - Modified to use PointerPos
* events rather than RawMouse events to
* position intuition's pointer. This
* allows Keymenu to co-exist with most
* mouse accelerators.
*
* 03/02/91 Ken Lowther V1.03 - Re-installed intuition pointer
* blanking option.
*
* 03/13/91 Ken Lowther V1.04 - Corrected to ignore topedge
* values in menu definitions (as
* intuition does).
*
* 04/13/91 Ken Lowther V1.05 - Corrected problem with subitems
* that are rendered to the left of their
* associated menu item.
*
* 04/13/91 Ken Lowther V1.05 - Implemented 2 stage activation
* sequence to allow intuition to get the
* menu active before positioning the
* pointer.
*
* 04/19/91 Ken Lowther V1.05 - NEWPOINTERPOS events are now
* generated when running under release
* 2.0. This allows keymenu to work with
* all the new screen resolutions that
* 2.0 provides.
*
*******************************************************************************
nolist
include "macros.i"
include "exec/types.i"
include "exec/strings.i"
include "exec/nodes.i"
include "exec/ports.i"
include "exec/execbase.i"
include "exec/ables.i"
include "exec/interrupts.i"
include "exec/memory.i"
include "devices/inputevent.i"
include "intuition/intuition.i"
include "libraries/dos.i"
include "libraries/dosextens.i"
include "hardware/custom.i"
include "hardware/dmabits.i"
include "keymenu-handler.i"
list
nomlist
xdef _dmaconr
xdef _dmacon
xdef _spr
*******************************************************************************
* *
* Displacements into Select routine. *
* *
*******************************************************************************
s_top equ si_top-si_jmp-2
s_adjacent_top equ si_adjacent_top-si_jmp-2
s_adjacent_up equ si_adjacent_up-si_jmp-2
s_up equ si_up-si_jmp-2
s_adjacent_right equ si_adjacent_right-si_jmp-2
s_right equ si_right-si_jmp-2
s_leftmost equ si_leftmost-si_jmp-2
s_adjacent_down equ si_adjacent_down-si_jmp-2
s_bottom equ si_bottom-si_jmp-2
s_adjacent_left equ si_adjacent_left-si_jmp-2
s_down equ si_down-si_jmp-2
s_left equ si_left-si_jmp-2
s_rightmost equ si_rightmost-si_jmp-2
gbl equr a4 ; handler global area
cseg
near code
*******************************************************************************
* *
* main *
* *
* This is the main routine of KeyMenu-Handler. It is where execution *
* begins. Here we perform the following functions: *
* 1) Initialize program. This consists of determining what task we *
* are and finding the public message port that the KeyMenu *
* program created for us. If the port doesn't exist or if *
* another task already owns it, we just exit (this can happen if *
* the user somehow manages to run this program instead of *
* KeyMenu). The global area behind the message port, created by *
* Keymenu, is updated with our task address, the signal number *
* to use to send messages to us and the address of our input *
* handler routine. We then signal KeyMenu that we are *
* initialized. *
* 2) Wait for one of two events to occur. Either a message has been *
* directed to us via the public message port or KeyMenu has *
* signalled us to stop. Process the event as appropriate. *
* 3) Step 2, above, is repeated until our 'active' flag is reset. *
* This occurs when, at our request, the input_handler sends a *
* message to us indicating it is ready to stop. We then cleanup *
* any resources we have allocated and return to AmigaDOS. *
* *
* Input Registers: *
* None. *
* *
* Output Registers: *
* None. *
* *
*******************************************************************************
main movem.l mainregs,-(sp) ; save entry registers
*-----------------------------------------------------------------------------*
* do initialization *
*-----------------------------------------------------------------------------*
move.l AbsExecBase,a6 ; setup base for exec.library
sub.l a1,a1 ; set to find our task
Call FindTask ; get pointer to our task
move.l d0,a2 ; get task address
clr.l pr_ConsoleTask(a2) ; clear console handler pointer
lea myport(pc),a1 ; pointer to port name
Call FindPort ; go find our port
tst.l d0 ; does it exist ?
beq main060 ; no, must have it, get out
move.l d0,gbl ; save pointer to our world
tst.l MP_SIGTASK(gbl) ; is a task already there ?
bne main060 ; yes, branch
*-----------------------------------------------------------------------------*
* everything seems ok, update our global area and signal KeyMenu to *
* go ahead and add our input_handler routine to the input.device *
*-----------------------------------------------------------------------------*
moveq.l #-1,d0
Call AllocSignal ; get a signal for our task
move.b d0,MP_SIGBIT(gbl) ; save the signal number
move.l a2,MP_SIGTASK(gbl) ; make our task the one to signal
move.l a2,gb_handtask(gbl)
lea input_handler(pc),a1 ; get addr of input handler code
move.l a1,gb_handler+IS_CODE(gbl) ; put it in interrupt struct
jsr dosignal ; go signal companion task
moveq.l #1,d4 ; set active flag
*-----------------------------------------------------------------------------*
* if we are still active, wait for something to happen *
*-----------------------------------------------------------------------------*
main010 tst.w d4 ; are we still active ?
beq main050 ; no, go clean things up
clr.l d1 ; clear work register
move.b MP_SIGBIT(gbl),d1 ; get signal bit number
bset.l d1,d0 ; create signal mask
bset.l #SIGBREAKB_CTRL_C,d0 ; set break bit
Call Wait ; wait for something to happen
*-----------------------------------------------------------------------------*
* An event occurred! Determine if KeyMenu signalled 'CTRL C' *
* telling us to stop. If not, there must be a message waiting on *
* the message port. *
*-----------------------------------------------------------------------------*
btst.l #SIGBREAKB_CTRL_C,d0 ; did user request us to stop ?
beq main015 ; no, branch
bset.b #FLAGB_Stop_requested,gb_flags(gbl) ; set stop requested
; this tells the input handler to
; stop the next time it is entered
bra main010 ; go wait for input handler to stop
*-----------------------------------------------------------------------------*
* get a message from the message port and determine what it is *
*-----------------------------------------------------------------------------*
main015 move.l gbl,a0 ; get address of message port
Call GetMsg ; get any message placed there
tst.l d0 ; was there a message queued ?
beq main010 ; no, branch
move.l d0,a2 ; save message address
cmp.w #req_stopped,LN_NAME(a2) ; stop message ?
bne main020 ; no, branch
*-----------------------------------------------------------------------------*
* A 'stop' message was received from the input handler. Clear our *
* 'active' flag. *
*-----------------------------------------------------------------------------*
clr.l d4 ; yes, clear active flag
main020 cmp.w #req_onsprite,LN_NAME(a2) ; request to turn sprites on ?
bne main030 ; no, branch
*-----------------------------------------------------------------------------*
* A 'onsprite' request was received from the input handler. *
* This causes us to turn sprites back on so the user can see *
* the pointer again (if we turned them off in the first place) *
*-----------------------------------------------------------------------------*
btst.b #FLAGB_Blanked,gb_flags2(gbl) ; did we turn sprites off ?
beq main040 ; no, don't turn them on
far data
move.w #DMAF_SPRITE+DMAF_SETCLR,_dmacon ; sprites on
near data
bra main040
main030 cmp.w #req_offsprite,LN_NAME(a2) ; request to turn sprites off ?
bne main040 ; no, branch
*-----------------------------------------------------------------------------*
* An 'offsprite' request was received from the input handler. This *
* causes us to turn off sprites to remove the pointer from the *
* view during menu operations. If sprites are already turned off, *
* we do nothing. *
*-----------------------------------------------------------------------------*
bclr.b #FLAGB_Blanked,gb_flags2(gbl)
far data
btst.b #DMAB_SPRITE,_dmaconr+1 ; are sprites on ?
near data
beq main040 ; no, branch
Call WaitTOF,gb_IBase(gbl) ; wait for the proper time
far data
move.w #DMAF_SPRITE,_dmacon ; turn sprites off
clr.w _spr+sd_dataa
clr.w _spr+sd_dataB
near data
bset.b #FLAGB_Blanked,gb_flags2(gbl) ; remember we turned sprites off
*-----------------------------------------------------------------------------*
* free the message we received and loop to see if there is more *
*-----------------------------------------------------------------------------*
main040 clr.l d0
move.l a2,a1 ; setup addr of block to free
move.w MN_LENGTH(a1),d0 ; setup length of block to free
Call FreeMem ; go free it
bra main015 ; loop for next message
myport portname
*-----------------------------------------------------------------------------*
* We are no longer active, cleanup after ourselves and get out *
*-----------------------------------------------------------------------------*
main050 move.l gbl,a0 ; get address of message port
Call GetMsg ; get any message placed there
tst.l d0 ; was there a message queued ?
beq main055 ; no, branch
move.l d0,a1 ; setup to free the block
clr.l d0
move.w MN_LENGTH(a1),d0 ; setup length of block to free
Call FreeMem ; go free it
bra main050 ; loop for next message
main055 clr.l d0
move.b MP_SIGBIT(gbl),d0 ; get signal number
Call FreeSignal ; go free it
Forbid
jsr dosignal ; go signal companion task
main060 movem.l (sp)+,mainregs ; restore entry registers
rts ; return to AmigaDOS
mainregs reg d1-d7/a0-a6
*******************************************************************************
* *
* dosignal *
* *
* Send a signal to our companion task (should be KeyMenu). *
* *
* Input Registers: *
* a4 - global work area *
* *
* Output Registers: *
* None. *
* *
*******************************************************************************
dosignal clr.l d1 ; clear work register
move.b gb_tasksignum(gbl),d1 ; get keymenu task signal number
bset.l d1,d0 ; create signal mask
move.l gb_task(gbl),a1 ; get task to signal
Call Signal ; signal the task that we are ready
rts
******************************************************************************
* *
* input_handler *
* *
* This routine is added to the input.device's list of handlers by the *
* KeyMenu program. It is called whenever an input event, such as a *
* keyboard press or mouse movement, occurs. In general, the input event *
* chain is scanned to see if the user has pressed any one of the *
* various keys that we care about. If so, the input event representing *
* that keypress is replaced with a mouse event(s) to accomplish *
* KeyMenu's purpose. Note that the memory associated with event(s) that *
* are removed from the list actually belongs to the creator of that *
* event. It is the event creator's responsibility to free this memory. *
* See the RKM for more info about input handlers and the input.device *
* *
* Input Registers: *
* a0 - input event chain, a forward reference linked list with the *
* last event in the chain containing a 'NULL' reference. *
* a1 - global work area *
* *
* Output Registers: *
* d0 - new input event chain *
* *
*******************************************************************************
input_handler
laste equr a1 ; last event handled in chain
ev equr a2 ; original event passed to us
ep equr a3 ; current event pointer
movem.l ihregs,-(sp) ; save registers
move.l a1,gbl ; setup pointer to our world
move.l a0,ev ; save pointer to input event chain
*-----------------------------------------------------------------------------*
* If 'stop' has been posted, check to see if there is currently a *
* menu active. If so, wait for the user to get out of it otherwise *
* send a 'stop' message (actually means 'ready to stop') to the *
* KeyMenu-Handler process. *
*-----------------------------------------------------------------------------*
btst.b #FLAGB_Stop_requested,gb_flags(gbl) ; stop requested ?
beq ih010 ; no, branch
btst.b #FLAGB_MActive,gb_flags(gbl) ; is a menu currently active ?
bne ih010 ; yes, branch
btst.b #FLAGB_Stopped,gb_flags(gbl) ; stop already been posted ?
bne ih010 ; yes, branch
moveq.l #req_stopped,d0 ; set type of request to send
jsr sendrequest ; go send it
bset.b #FLAGB_Stopped,gb_flags(gbl) ; indicate stop has been posted
*-----------------------------------------------------------------------------*
* Begin stepping through the input event chain *
*-----------------------------------------------------------------------------*
ih010 FORBID ; don't let anyone mess with events
sub.l laste,laste ; clear last event register
move.l ev,ep ; setup event work register
bclr.b #FLAGB_Events_inserted,gb_flags(gbl) ; clear inserted flag
bra ih040 ; go see if an event exists
ih015 btst.b #FLAGB_MActive,gb_flags(gbl) ; is a menu currently active ?
beq ih017 ; no, branch
btst.b #FLAGB_ASC,gb_flags2(gbl) ; is activation sequence complete ?
bne ih017 ; yes, branch
jsr Check_Menu_Active ; go see if the menu is active yet
bra ih045 ; get out until menu is active
ih017 cmp.b #IECLASS_RAWKEY,ie_Class(ep) ; Raw key event ?
bne ih025 ; no, branch
*-----------------------------------------------------------------------------*
* This is a RAWKEY event (keypress/keyrelease). *
*-----------------------------------------------------------------------------*
jsr Check_RawKey_Event ; go look at this one
beq ih030 ; do we keep it ? yes, branch
move.l laste,d0 ; was there a previous event ?
bne ih020 ; yes, branch
move.l ie_NextEvent(ep),ev ; drop the event
bra ih035
ih020 move.l ie_NextEvent(ep),ie_NextEvent(laste)
bra ih035 ; loop
*-----------------------------------------------------------------------------*
* Here we look for a 'MENUDOWN' event. If this occurs while we have *
* a menu active, it indicates that the user pressed the right mouse *
* button intending to take over menu selection with the mouse. *
*-----------------------------------------------------------------------------*
ih025 cmp.b #IECLASS_RAWMOUSE,ie_Class(ep) ; is this a raw mouse event ?
bne ih030 ; no, branch
cmp.w #MENUDOWN,ie_Code(ep) ; is it a menu down event ?
bne ih030 ; no, branch
btst.b #FLAGB_MActive,gb_flags(gbl) ; is a menu in progress ?
beq ih030 ; no, branch
bclr.b #FLAGB_MActive,gb_flags(gbl) ; give control of menu to mouse
moveq.l #req_onsprite,d0
jsr sendrequest ; go reset intuition pointer
*-----------------------------------------------------------------------------*
* Now we look to see if we inserted any events in the chain. If so, *
* we must get out. This is because we only have a fixed number of *
* input event areas allocated (3) and they can be used only once *
* per invocation of the handler. This could be a potential problem *
* in that we could miss events that we care about (since we don't *
* look at the remaining events in the event chain). However, this *
* is nothing that would cause harm to the system. It would just *
* appear to the user as though a keypress intended to cause a menu *
* operation didn't take. This is better than incuring the overhead *
* and buffer management problems associated with dynamically *
* allocating input events. *
*-----------------------------------------------------------------------------*
ih030 move.l ep,laste ; save this event
ih035 btst.b #FLAGB_Events_inserted,gb_flags(gbl) ; were events inserted?
bne ih045 ; yes, branch
*-----------------------------------------------------------------------------*
* Setup to process the next event if one exists, otherwise get out *
*-----------------------------------------------------------------------------*
move.l ie_NextEvent(ep),ep ; get next event
ih040 move.l ep,d0 ; set cc
bne ih015 ; go check it
ih045 PERMIT
move.l ev,d0 ; pass event on
movem.l (sp)+,ihregs ; restore registers
rts ; return to input device
ihregs reg a0/a1/a2/a3/a4/a6
*******************************************************************************
* *
* sendrequest *
* *
* This routine is called by the input handler when it wishes to send a *
* request message to the KeyMenu-Handler process. There are currently *
* three kinds of messages that may be sent: *
* 1) req_offsprite, to blank the intuition pointer during menu *
* operations. *
* 2) req_onsprite, to restore the intuition pointer when menu *
* operations are finished. *
* 3) req_stopped, to signal that the handler is ready to stop. *
* Sendrequest is always called regardless of the setting of the hide *
* intuition pointer option. This is where we determine whether or not *
* to actually send the request. *
* *
* Input Registers: *
* d0 - type of request to be sent *
* a4 - global work area *
* *
* Output Registers: *
* none. *
* *
*******************************************************************************
sendrequest movem.l sendreqregs,-(sp) ; save entry registers
btst.b #FLAGB_Blank_pointer,gb_flags(gbl) ; blank pointer option on ?
bne sendreq010 ; yes, branch
cmp.w #req_stopped,d0 ; is this a 'stopped' request ?
bne sendreq020 ; no, branch
sendreq010 move.l d0,d2 ; save request type
move.l #MEMF_CLEAR+MEMF_PUBLIC,d1 ; set attributes
move.l #MN_SIZE,d0 ; set size of block
Call AllocMem ; go allocate a block
tst.l d0 ; was a block given to us ?
beq sendreq020 ; no, branch
move.l d0,a1 ; yes, save pointer to block
move.w d2,LN_NAME(a1) ; format message
clr.l MN_REPLYPORT(a1)
move.w #MN_SIZE,MN_LENGTH(a1)
move.l gbl,a0
Call PutMsg ; write it to the port
sendreq020 movem.l (sp)+,sendreqregs ; restore registers
rts ; return to caller
sendreqregs reg a0/a1/d0-d2
*******************************************************************************
* *
* Check_Menu_Active *
* *
* This routine checks the active window to see if the menu has been *
* activated yet. If so, we finish our activation sequence by *
* positioning the pointer on the desired menuitem. Otherwise we wait *
* for intuition to get around to activating the menu. *
* *
* Input Registers: *
* a4 - global work area *
* *
* Output Registers: *
* none *
* *
*******************************************************************************
Check_Menu_Active
movem.l cmaregs,-(sp) ; save registers
move.l gb_window(gbl),a1 ; get pointer to the window
move.l gb_IBase(gbl),a2 ; get intuitionbase
cmp.l ib_ActiveWindow(a2),a1 ; is same window active ?
beq cma005 ; yes, branch
cma003 bclr.b #FLAGB_MActive,gb_flags(gbl) ; clear our activation flag
moveq.l #req_onsprite,d0
jsr sendrequest ; go reset intuition pointer
bra cma010
cma005 move.l wd_Flags(a1),d0 ; get window's flags
btst.l #MENUSTATE_B,d0 ; is the menu active ?
bne cma007 ; yes, branch
move.b gb_waitcnt(gbl),d0 ; no, get wait counter
add.b #1,d0 ; bump counter
move.b d0,gb_waitcnt(gbl) ; save the counter
beq cma003 ; if we wrap to zero, reset
bra cma010 ; wait somemore
cma007 moveq.l #2,d0 ; indicate 2 events to be built
jsr dobuild ; go build the necessary events
bset.b #FLAGB_ASC,gb_flags2(gbl) ; indicate activation complete
cma010 movem.l (sp)+,cmaregs ; restore registers
rts ; return to caller
cmaregs reg a0-a2
*******************************************************************************
* *
* Check_RawKey_Event *
* *
* This routine checks each RAWKEY event (keypress/keyrelease) to see if *
* it is one that we are interested in. If it is, the event that is *
* passed to us is replaced with events to do the appropriate KeyMenu *
* function. Events that have no meaning for us are passed back to the *
* caller indicating that they should remain in the input event chain. *
* *
* Input Registers: *
* a3 - rawkey event to be checked *
* a4 - global work area *
* *
* Output Registers: *
* d0 - 0=discard the event, 1=keep the event *
* *
*******************************************************************************
Check_RawKey_Event
movem.l creregs,-(sp) ; save registers
clr.l d0
btst.b #IEQUALIFIER_REPEAT_R,ie_Qualifier(a3) ; is it a repeat ?
beq cre003 ; no, branch
btst.b #FLAGB_Repeat_skipped,gb_flags(gbl) ; have we skipped one ?
bne cre004 ; yes, branch
bset.b #FLAGB_Repeat_skipped,gb_flags(gbl) ; indicate repeat skipped
bra cre_remove ; remove it from the input chain
cre003 bclr.b #FLAGB_Repeat_skipped,gb_flags(gbl) ; clear repeat skipped
cre004 btst.b #FLAGB_MActive,gb_flags(gbl) ; is a menu currently active ?
bne cre035 ; yes, branch
*-----------------------------------------------------------------------------*
* A menu is not currently active, check to see if one is being *
* activated (keypress of the configured activation key). *
*-----------------------------------------------------------------------------*
move.b gb_AKey(gbl),d0 ; get configured activation key code
cmp.w ie_Code(a3),d0 ; Menu Activate Key ?
bne cre010 ; no, branch
*-----------------------------------------------------------------------------*
* The user pressed the menu activation key, set a flag indicating *
* that fact and wait to see if the key is released without pressing *
* any other keys. *
*-----------------------------------------------------------------------------*
bset.b #FLAGB_AKey_down,gb_flags(gbl) ; indicate Menu activate key
; down
cre005 bra cre_remove ; remove this event
cre010 bset.l #IECODE_UP_PREFIX_R,d0 ; form keyrelease keycode
cmp.w ie_Code(a3),d0 ; is it activate menu keyrelease ?
beq cre014 ; yes, branch
cre012 bclr.b #FLAGB_AKey_down,gb_flags(gbl) ; clear activate key down
bra cre_keep ; keep this event
cre014 btst.b #FLAGB_AKey_down,gb_flags(gbl) ; is activate key down still
; posted ?
beq cre012 ; no, branch
*-----------------------------------------------------------------------------*
* The user pressed and released the menu activation key without *
* hitting any other keys, find the current window and see if it has *
* a menu. *
*-----------------------------------------------------------------------------*
move.l gb_IBase(gbl),a5 ; get intuitionbase
move.l ib_ActiveWindow(a5),d0 ; get current window
beq cre005 ; if none, branch
move.l d0,a1 ; save pointer to current window
move.l wd_MenuStrip(a1),d0 ; get window's menu
beq cre005 ; if none, branch
move.l d0,a0 ; save menu for use later
move.l wd_Flags(a1),d0 ; get window's flags
btst.l #MENUSTATE_B,d0 ; is a menu already active ?
bne cre005 ; yes, branch
*-----------------------------------------------------------------------------*
* The current window has a menu, check the RMBTRAP flag. If this is *
* set and the user didn't specify that we can clear it, then we *
* can't use this menu. *
*-----------------------------------------------------------------------------*
btst.l #RMBTRAP_B,d0 ; is RMBTRAP set in window ?
beq cre015 ; no, branch
btst.b #FLAGB_Clear_rmbtrap,gb_flags(gbl) ; clear rmbtrap option
; set ?
beq cre005 ; no, ignore the menu
bclr.l #RMBTRAP_B,d0 ; clear RMBTRAP bit
move.l d0,wd_Flags(a1) ; update window's flags
*-----------------------------------------------------------------------------*
* Finally, a menu we can use. Update our globals. *
*-----------------------------------------------------------------------------*
cre015 move.l a0,gb_menu(gbl) ; update our Menu pointer
move.l a1,gb_window(gbl) ; update our window pointer
*-----------------------------------------------------------------------------*
* Now look to see if the menu and menu item saved in our globals is *
* still valid for this menu. If so, we will position the mouse on *
* them otherwise we'll put the mouse on the topmost item in the *
* leftmost menu. *
*-----------------------------------------------------------------------------*
move.l gb_currentmenu(gbl),a1 ; get saved menu
jsr Verify_Item ; go verify currentmenu
bne cre020 ; does it exist ? yes, use it
move.w #s_leftmost,d0 ; no, setup to find leftmost menu
jsr Select_Item ; go select a Menu
move.l d0,gb_currentmenu(gbl) ; update our globals with new menu
cre020 move.l gb_currentmenu(gbl),a0 ; get current menu
move.l mu_FirstItem(a0),a0 ; point to first menu item
move.l gb_currentitem(gbl),a1 ; get current menu item
jsr Verify_Item ; go verify current item
bne cre025 ; does it exist ? yes, branch
move.w #s_top,d0 ; no, setup to find top menuitem
jsr Select_Item ; go select menu item
move.l d0,gb_currentitem(gbl) ; update our globals
*-----------------------------------------------------------------------------*
* Save the current mouse position so we can put it back where we *
* found it when we're done. set/clear various flags reflecting our *
* current state. One event is inserted in the event chain. *
* A rawmouse menudown event that causes intuition to activate the *
* menu. The second stage of the activation sequence will position *
* the pointer on the desired menu item (see Check_Active_Menu) *
*-----------------------------------------------------------------------------*
cre025 move.w ib_MouseX(a5),gb_old_MouseX(gbl) ; save current X
move.w ib_MouseY(a5),gb_old_MouseY(gbl) ; save current Y
btst.b #FLAGB_Release2,gb_flags2(gbl) ; release 2 ?
beq cre026 ; no, branch
move.l gb_window(gbl),a5 ; get current window
move.l wd_WScreen(a5),a5 ; get window's screen
move.w sc_MouseX(a5),gb_old_MouseX(gbl) ; save current X
move.w sc_MouseY(a5),gb_old_MouseY(gbl) ; save curreny Y
cre026 clr.l gb_currentsubitem(gbl) ; no subitem at present
move.w #MENUDOWN,d0 ; setup to insert a menudown event
move.l a3,a1 ; event to attach new event to
jsr Insert_RawMouse_Event ; go insert the rawmouse event
bclr.b #FLAGB_AKey_down,gb_flags(gbl) ; no longer waiting for
; activate key down event
clr.b gb_waitcnt(gbl) ; clear wait counter
bclr.b #FLAGB_ASC,gb_flags2(gbl) ; indicate activation in progress
move.l #req_offsprite,d0 ; setup to send request
cre027 bchg.b #FLAGB_MActive,gb_flags(gbl) ; invert menu active bit
jsr sendrequest ; send pointer req to our task
bra cre_remove ; go to common return
*-----------------------------------------------------------------------------*
* A menu is currently active, check for the various keys that we *
* care about. *
*-----------------------------------------------------------------------------*
cre035 move.b gb_DKey(gbl),d0
cmp.w ie_Code(a3),d0 ; Deactivate key ?
bne cre040 ; no, branch
*-----------------------------------------------------------------------------*
* The menu 'deactivate' key was pressed. Three events are inserted *
* in the event chain. They consist of a pointerpos event to *
* position the pointer in the menu strip followed by a rawmouse *
* menuup event that causes intuition to deactivate the menu without *
* selecting anything followed by another pointerpos event to put *
* the pointer back where we found it when the menu was activated. *
*-----------------------------------------------------------------------------*
moveq.l #3,d0 ; build 2 events
jsr dobuild ; go build mouse event(s)
move.w #MENUUP,d0 ; setup for a menu up rawmouse event
move.l a0,a1 ; event to attach new event to
jsr Insert_RawMouse_Event ; go insert the a rawmouse event
move.l #req_onsprite,d0 ; setup to restore pointer
bra cre027 ; get out
cre040 move.b gb_SKey(gbl),d0
cmp.w ie_Code(a3),d0 ; Select Key ?
bne cre055 ; yes, branch
*-----------------------------------------------------------------------------*
* The menu 'select' key was pressed. Two events are inserted in the *
* event chain. They consist of a menuup rawmouse event to select *
* the current menu item, followed by a pointer event to put the *
* pointer back where we found it when the menu was activated. *
*-----------------------------------------------------------------------------*
move.l a3,a1 ; event to attach new ones to
move.w #MENUUP,d0 ; set type of rawmouse event
jsr Insert_RawMouse_Event ; go insert a menuup event
move.w gb_old_MouseX(gbl),d0 ; get saved mouse x coordinate
move.w gb_old_MouseY(gbl),d1 ; get saved mouse y cooridnate
move.l a0,a1 ; event to attach new event to
lea gb_pp1(gbl),a0 ; setup for release 2.0 just in case
move.l a0,gb_ppos1+ie_EventAddress(gbl)
lea gb_ppos1(gbl),a0 ; new event to be inserted
jsr Insert_PointerPos_Event
move.l #req_onsprite,d0 ; setup to restore pointer
bra cre027 ; get out
cre055 move.b gb_RightKey(gbl),d0
cmp.w ie_Code(a3),d0 ; Move Right ?
bne cre060 ; no, branch
move.w #s_adjacent_right,d1 ; 1st selection choice
move.w #s_right,d2 ; 2nd selection choice
move.w #s_leftmost,d3 ; 3rd selection choice
bra cre065
cre060 move.b gb_LeftKey(gbl),d0
cmp.w ie_Code(a3),d0 ; Move Left ?
bne cre125 ; no, branch
move.w #s_adjacent_left,d1 ; 1st selection choice
move.w #s_left,d2 ; 2nd selection choice
move.w #s_rightmost,d3 ; 3rd selection choice
cre065 move.b ie_Qualifier+1(a3),d0 ; get key qualifier
and.b gb_Qual(gbl),d0 ; was qualifier key present ?
beq cre067 ; no,branch
*-----------------------------------------------------------------------------*
* The menu 'right' or 'left' key was pressed. See if a qualifier *
* key was also present. If so, we move to either rightmost or *
* leftmost menu. *
*-----------------------------------------------------------------------------*
move.w #s_rightmost,d0 ; select rightmost
cmp.w d0,d3 ; same selection ?
bne cre107 ; no, branch
move.w #s_leftmost,d0 ; select leftmost
bra cre107 ; go choose the menu
*-----------------------------------------------------------------------------*
* The menu 'right' or 'left' key was pressed. Now we must see if *
* a subitem list exists for the current menu item. *
*-----------------------------------------------------------------------------*
cre067 move.l gb_currentitem(gbl),a0 ; get current menu item ptr
move.l mi_SubItem(a0),a1 ; get its menu subitem ptr, if any
move.l a1,d0 ; set cc
beq cre100 ; no subitems on this menu, branch
*-----------------------------------------------------------------------------*
* There are subitems attached to this menu item. Some explanation *
* is in order here. With Intuition, menu subitems can be rendered *
* anywhere on the menu display as long as at least one pixel of the *
* menu subitem overlaps a pixel of its associated menu item. *
* Generally, subitems are designed to appear either to the right of *
* its associated menu item or to the left. This affects our *
* interpretation of what the user wants to do when they press *
* either the menu right or menu left key. For example, if the menu *
* subitems are positioned to the right of the menu item and the *
* menu right key is pressed, this means that the user intends to *
* step into the menu subitem list. If the menu subitems are *
* positioned on the left and the menu right key is pressed, the *
* user wants to step to the next list of menu items on the right *
* (or wrap to the first set of menu items if we are positioned on *
* the rightmost menu item). Here we check the leftedge of the *
* subitem to see if it is greater than zero to determine if the *
* subitem's leftedge is to the left of the menu item's leftedge. *
* The result of this comparison is saved in d4 and is used later *
* in determining what the user's intentions are. *
*-----------------------------------------------------------------------------*
clr.w d0
cmp.w mi_LeftEdge(a1),d0 ; check subitem's leftedge
sgt d4 ; save comparison result
tst.l gb_currentsubitem(gbl) ; are we processing subitems ?
bne cre080 ; yes, branch
*-----------------------------------------------------------------------------*
* We are positioned on a menu item that has subitems attached and *
* the user has pressed the menu right or menu left key. Determine *
* what their intention is. Either they want to step into the *
* subitem list or they want to select the next menu item. *
*-----------------------------------------------------------------------------*
clr.l d0
move.b gb_RightKey(gbl),d0 ; setup for compare
cmp.w ie_Code(a3),d0 ; right key ?
bne cre070 ; no, branch
tst.b d4 ; are subitems on menu items left ?
beq cre075 ; no, step into the subitem list
bra cre100 ; yes, step to next menu item list
cre070 tst.b d4 ; are subitems on menu items left ?
beq cre100 ; no, step to next menu item list
; yes, step into the subitem list
*-----------------------------------------------------------------------------*
* The user wants to step into the subitem list. Select the topmost *
* adjacent subitem in the list. (Note: there can be subitems *
* positioned horizontally as well as vertically) *
*-----------------------------------------------------------------------------*
cre075 move.w #s_adjacent_top,d0 ; set to select the topmost subitem
move.l a1,a0 ; list of subitems to choose from
jsr Select_Item ; go find the subitem
move.l d0,gb_currentsubitem(gbl) ; save it in our globals
bra cre085 ; go generate an event
*-----------------------------------------------------------------------------*
* We are currently positioned on a menu subitem and the user has *
* pressed either the menu right key or menu left key. Determine *
* what their intention is. If there is another subitem positioned *
* adjacent to the current subitem in the direction of the key that *
* was pressed, that subitem will be selected. Otherwise, the user *
* wants to step out of the subitem list. *
*-----------------------------------------------------------------------------*
cre080 move.l d1,d0 ; get 1st selection choice
move.l a1,a0 ; list of subitems to choose from
move.l gb_currentsubitem(gbl),a1 ; supply current subitem
jsr Select_Item ; go select next subitem
cmp.l d0,a1 ; same item selected ?
beq cre090 ; yes, get out of the subitem list
move.l d0,gb_currentsubitem(gbl) ; no, save new subitem
cre085 moveq.l #1,d0 ; set to build only one event
bra cre175 ; go generate an event
*-----------------------------------------------------------------------------*
* The user wants to step out of the subitem list. Determine whether *
* they want to go back to the menu item associated with the subitem *
* list or to the next menu item. *
*-----------------------------------------------------------------------------*
cre090 clr.l gb_currentsubitem(gbl) ; clear current subitem pointer
clr.l d0
move.b gb_RightKey(gbl),d0 ; setup for compare
cmp.w ie_Code(a3),d0 ; right key ?
bne cre095 ; no, branch
tst.b d4 ; are subitems on menu items left ?
bne cre085 ; yes, go back to subitems menu item
bra cre100 ; no, go select next menu item list
cre095 tst.b d4 ; are subitems on menu items left ?
beq cre085 ; no, go back to subitems menu item
*-----------------------------------------------------------------------------*
* Select a menu item. (Note: there can be menu items positioned *
* horizontally as well as vertically) *
*-----------------------------------------------------------------------------*
cre100 move.l d1,d0 ; get 1st selection choice
move.l gb_currentmenu(gbl),a0 ; get current menu
move.l mu_FirstItem(a0),a0 ; list of items to choose from
move.l gb_currentitem(gbl),a1 ; get current menu item
jsr Select_Item ; go select an item
cmp.l d0,a1 ; same item selected ?
bne cre115 ; no, use the new item, branch
*-----------------------------------------------------------------------------*
* There are no menu items positioned in the horizontal direction of *
* the key that was pressed, so we must step to the next menu. *
*-----------------------------------------------------------------------------*
move.l d2,d0 ; get 2nd selection choice
move.l gb_menu(gbl),a0 ; list of menus to choose from
move.l gb_currentmenu(gbl),a1 ; get current menu
jsr Select_Item ; go select a menu
cmp.l d0,a1 ; same menu selected ?
beq cre105 ; yes, branch
move.l d0,gb_currentmenu(gbl) ; no, use the new menu
bra cre110 ; go select an item in the menu
*-----------------------------------------------------------------------------*
* There are no menus in the horizontal direction of the key that *
* was pressed. We will interpret this to mean that the user wants *
* to wrap to the opposite end of the menu strip. For example, if we *
* are currently on the rightmost menu and the user presses the menu *
* right key, we will wrap around to the leftmost menu. *
*-----------------------------------------------------------------------------*
cre105 move.l d3,d0 ; set 3rd selection choice
cre107 move.l gb_menu(gbl),a0 ; list of menus to choose from
jsr Select_Item ; go select again
move.l d0,gb_currentmenu(gbl) ; save new menu
cre110 move.w #s_top,d0 ; set to select topmost menu item
move.l gb_currentmenu(gbl),a0 ; get current menu
move.l mu_FirstItem(a0),a0 ; list of items to choose from
jsr Select_Item ; go select a menu item
move.l d0,gb_currentitem(gbl) ; save new item
*-----------------------------------------------------------------------------*
* Normally, we will generate only one event. A pointerpos event to *
* position the pointer on the desired menu item or subitem. Here we *
* have determined that a new menu is to be selected. This requires *
* us to generate 2 events. The first will be a pointerpos event to *
* position the pointer in the menu strip over the menu that we want *
* to select. This causes Intuition to remove the rendering of the *
* current menu from the display and render the menu that we are *
* selecting. The second event will be a pointerpos event to *
* position the pointer on the menu item that we have chosen. *
*-----------------------------------------------------------------------------*
moveq.l #2,d0 ; set number of events to build
bra cre120
cre115 move.l d0,gb_currentitem(gbl) ; save new item
moveq.l #1,d0 ; set number of events to build
cre120 clr.l gb_currentsubitem(gbl) ; clear current subitem pointer
bra cre175 ; go generate event(s)
cre125 move.b gb_DownKey(gbl),d0 ; setup for compare
cmp.w ie_Code(a3),d0 ; Down key ?
bne cre130 ; no, branch
move.w #s_adjacent_up,d1 ; 1st selection choice
move.w #s_up,d2 ; 2nd selection choice
move.w #s_top,d3 ; 3rd selection choice
bra cre135 ; go handle keypress
cre130 move.b gb_UpKey(gbl),d0 ; setup for compare
cmp.w ie_Code(a3),d0 ; Up key ?
bne cre_keep ; no, pass this event on
move.w #s_adjacent_down,d1 ; 1st selection choice
move.w #s_down,d2 ; 2nd selection choice
move.w #s_bottom,d3 ; 3rd selection choice
*-----------------------------------------------------------------------------*
* The menu 'up' or 'down' key was pressed. If we are currently *
* positioned in a subitem menu, setup to select the appropriate *
* subitem otherwise setup to select the appropriate menu item. *
*-----------------------------------------------------------------------------*
cre135 moveq.l #1,d4 ; set default # events to be created
tst.l gb_currentsubitem(gbl) ; are we processing subitems ?
beq cre140 ; no, branch
move.l gb_currentsubitem(gbl),a1 ; supply parameters to process
move.l gb_currentitem(gbl),a0 ; menu subitems
move.l mi_SubItem(a0),a0
bra cre145
cre140 move.l gb_currentitem(gbl),a1 ; supply parameters to process menu
move.l gb_currentmenu(gbl),a0 ; items
move.l mu_FirstItem(a0),a0
*-----------------------------------------------------------------------------*
* Here we check to see if there are subitems attached to the *
* current menu item. If so, we will generate 2 events. The first *
* will be a pointerpos event to position the pointer on the menu *
* strip. The second will be a pointerpos event to position the *
* pointer on the desired menu item. This is done to cause Intuition *
* to remove the subitem's rendering from the display in case it *
* overlaps onto the menu item being selected. Without this, we *
* would tell Intuition to position the mouse on the new menu item *
* but the overlapping subitems from the current menu item would *
* still be displayed causing us to select a menu subitem instead of *
* the menu item that we intended to select. *
*-----------------------------------------------------------------------------*
tst.l mi_SubItem(a1) ; are there subitems attached to
; this menu item ?
beq cre145 ; no, branch
moveq.l #2,d4 ; yes, use 2 events to select item
cre145 move.b ie_Qualifier+1(a3),d0 ; get key qualifier
and.b gb_Qual(gbl),d0 ; was qualifier key present ?
beq cre147 ; no, branch
*-----------------------------------------------------------------------------*
* See if a qualifier key was also present. If so, we move to either *
* topmost or bottommost menu or submenu item. *
*-----------------------------------------------------------------------------*
move.w #s_bottom,d0 ; select bottom
cmp.w d0,d3 ; same selection ?
bne cre153 ; no, branch
move.w #s_top,d0 ; select top
bra cre153
cre147 move.l d1,d0 ; get 1st selection choice
jsr Select_Item ; go select a menuitem or subitem
cmp.l d0,a1 ; same item selected ?
bne cre155 ; no, use the new one
move.l d2,d0 ; get 2nd selection choice
jsr Select_Item ; select again
cre150 cmp.l d0,a1 ; same item selected ?
bne cre155 ; no, use new item
move.l d3,d0 ; get 3rd selection choice
cre153 jsr Select_Item ; go select again
cre155 move.l d0,a1 ; save new item
cre160 tst.l gb_currentsubitem(gbl) ; are we processing subitems ?
beq cre165 ; no, branch
move.l a1,gb_currentsubitem(gbl) ; yes, save new subitem
bra cre170
cre165 move.l a1,gb_currentitem(gbl) ; save new item
cre170 move.l d4,d0 ; get # of events to be generated
cre175 jsr dobuild ; go build our events
*-----------------------------------------------------------------------------*
* Indicate that the original input event passed to this routine is *
* to be removed from the input event chain and return. *
*-----------------------------------------------------------------------------*
cre_remove moveq.l #1,d0 ; indicate old event to be removed
bra cre_exit ; go to common return
*-----------------------------------------------------------------------------*
* Indicate that the original input event passed to this routine is *
* to be kept in the input event chain and return. *
*-----------------------------------------------------------------------------*
cre_keep clr.l d0 ; indicate old event to be kept
cre_exit movem.l (sp)+,creregs ; restore registers
rts ; return to caller
creregs reg a1-a3/a5/d2-d4
*******************************************************************************
* *
* dobuild *
* *
* This routine is called by Check_RawKey_Event to perform a general *
* call to the Build_PointerPos_Event routine. *
* *
* Input Registers: *
* a3 - input event to attach new events to *
* a4 - global work area *
* *
* Output Registers: *
* a0 - new input event *
* a1 - original input event *
* *
*******************************************************************************
dobuild move.l a3,a1 ; pass original input event
db010 lea gb_pp2(gbl),a0 ; setup for release 2 just in case
move.l a0,gb_ppos2+ie_EventAddress(gbl)
lea gb_ppos2(gbl),a0 ; point to our input event area
jsr Build_PointerPos_Event ; go create our input events
rts ; return to caller
*******************************************************************************
* *
* Verify_Item *
* *
* This routine is called by Check_RawKey_Event to verify if a menu or *
* menu item is a member of a provided list of menu/menu items. *
* *
* Input Registers: *
* a0 - menu/menu item list *
* a1 - item to be verified. *
* *
* Output Registers: *
* d0 - 0=no match, 1=match *
* *
*******************************************************************************
Verify_Item movem.l viregs,-(sp)
vi010 cmp.l a0,a1 ; does this item match ?
beq vi015 ; yes, branch
move.l im_NextItem(a0),d0 ; get next item's address
beq vi020 ; entire list scanned, branch
move.l d0,a0 ; use next item's address
bra vi010 ; loop to check next item
vi015 moveq.l #1,d0 ; indicate that the item exists
vi020 movem.l (sp)+,viregs
rts
viregs reg a0/a1
*******************************************************************************
* *
* Select_Item *
* *
* This routine is called to select a menu, menu item or menu subitem. *
* Given a list of items to choose from, the attribute of the item *
* desired and the current item; this routine attempts to find a new *
* item that matches the desired attribute. For example, if d0 contains *
* 's_up' the list of items provided is scanned to find the closest item *
* that is physically above the current item on the display. *
* *
* Input Registers: *
* a0 - menu/menu item/menu subitem list *
* a1 - current item *
* d0 - type of item desired in relation to current item *
* *
* Output Registers: *
* d0 - selected item (or current item if no item was selected) *
* *
*******************************************************************************
Select_Item
select_type equr d0 ; select type & return value
item equr a0 ; item list
currentitem equr a1 ; currentitem
returnitem equr a2 ; return item
work equr d1 ; work register
*-----------------------------------------------------------------------------*
* 'returnitem' contains the address of the item that is being *
* considered for return to the calling routine. Here we create a *
* dummy item on the stack that contains extreme values for topedge *
* and leftedge. The address of this entry is loaded into *
* 'returnitem' to give us an initial entry to compare against. *
* For example, if 's_leftmost' is the attribute of the item that we *
* are searching for, the leftedge field in the dummy entry would *
* contain 32768. In an effort to find the 'leftmost' item in the *
* list, the 'si_leftmost' portion of this routine will compare the *
* leftedge of each item in the list with the leftedge of *
* 'returnitem'. When an item is found with a leftedge that is less *
* than returnitem's, its address is placed in returnitem. When the *
* end of the list is reached, the item with the lowest leftedge *
* should be contained in 'returnitem' *
*-----------------------------------------------------------------------------*
link a5,#-im_size
movem.l siregs,-(sp)
move.w #32767,work
cmp.w #s_leftmost,select_type
ble si010
move.w #-32768,work
si010 lea -im_size(a5),returnitem
move.w work,im_TopEdge(returnitem) ; setup dummy item
move.w work,im_LeftEdge(returnitem)
bra si_jmp ; go to computed jump
si_adjacent_up
move.w im_LeftEdge(item),work
cmp.w im_LeftEdge(currentitem),work
bne si_check_end
si_up move.w im_TopEdge(item),work
cmp.w im_TopEdge(currentitem),work
ble si_check_end
si_top
si_adjacent_top
move.w im_TopEdge(item),work
cmp.w im_TopEdge(returnitem),work
bge si015
move.l item,returnitem
si015 cmp.w #s_adjacent_top,select_type
bne si_check_end
move.w im_TopEdge(item),work
cmp.w im_TopEdge(returnitem),work
bne si_check_end
move.w im_LeftEdge(item),work
cmp.w im_LeftEdge(returnitem),work
bge si_check_end
move.l item,returnitem
bra si_check_end
si_adjacent_right
move.w im_TopEdge(item),work
cmp.w im_TopEdge(currentitem),work
bne si_check_end
si_right move.w im_LeftEdge(item),work
cmp.w im_LeftEdge(currentitem),work
ble si_check_end
si_leftmost move.w im_LeftEdge(item),work
cmp.w im_LeftEdge(returnitem),work
bge si_check_end
move.l item,returnitem
bra si_check_end
si_adjacent_down
move.w im_LeftEdge(item),work
cmp.w im_LeftEdge(currentitem),work
bne si_check_end
si_down move.w im_TopEdge(item),work
cmp.w im_TopEdge(currentitem),work
bge si_check_end
si_bottom move.w im_TopEdge(item),work
cmp.w im_TopEdge(returnitem),work
ble si_check_end
move.l item,returnitem
bra si_check_end
si_adjacent_left
move.w im_TopEdge(item),work
cmp.w im_TopEdge(currentitem),work
bne si_check_end
si_left move.w im_LeftEdge(item),work
cmp.w im_LeftEdge(currentitem),work
bge si_check_end
si_rightmost
move.w im_LeftEdge(item),work
cmp.w im_LeftEdge(returnitem),work
ble si_check_end
move.l item,returnitem
si_check_end
move.l im_NextItem(item),item
move.l item,work ; set cc
beq si_end
si_jmp jmp (pc,d0.w) ; jump to proper routine
si_end lea -im_size(a5),item
cmp.l item,returnitem ; still pointing to dummy item ?
bne si_return ; no, branch
move.l currentitem,returnitem ; yes, pass currentitem back
si_return move.l returnitem,d0 ; set return
movem.l (sp)+,siregs ; restore regs
unlk a5 ; remove area from stack
rts ; return to caller
siregs reg d1/a0-a2
*******************************************************************************
* *
* Insert_PointerPos_Event *
* *
* This routine creates a pointerpos event and attaches it to the input *
* event provided. *
* *
* Input Registers: *
* a0 - new event to be inserted *
* a1 - input event to attach new event to *
* d0 - Mouse X coordinate to place in new event *
* d1 - Mouse Y coordinate to place in new event *
* *
* Output Registers: *
* none. *
* *
*******************************************************************************
Insert_PointerPos_Event
btst.b #FLAGB_Release2,gb_flags2(gbl) ; release 2.0 ?
bne ipe010 ; yes, branch
move.b #IECLASS_POINTERPOS,ie_Class(a0) ; build mousemove event
move.w #IECODE_NOBUTTON,ie_Code(a0)
move.w d0,ie_X(a0) ; set coordinates
move.w d1,ie_Y(a0)
bra ire010
ipe010 move.b #IECLASS_NEWPOINTERPOS,ie_Class(a0)
move.b #IESUBCLASS_PIXEL,ie_SubClass(a0)
clr.w ie_Code(a0)
clr.w ie_Qualifier(a0)
move.l ie_NextEvent(a1),ie_NextEvent(a0) ; chain to original event
move.l a0,ie_NextEvent(a1)
move.l ie_EventAddress(a0),a0
move.l gb_window(gbl),a1 ; get current window
move.l wd_WScreen(a1),iepp_Screen(a0) ; supply screen
move.w d0,iepp_PositionX(a0) ; supply pointer
move.w d1,iepp_PositionY(a0) ; coordinates
rts
*******************************************************************************
* *
* Insert_RawMouse_Event *
* *
* This routine creates a rawmouse event and attaches it to the input *
* event provided. *
* *
* Input Registers: *
* a1 - input event to attach new event to *
* d0 - type of rawmouse event *
* *
* Output Registers: *
* none. *
* *
*******************************************************************************
Insert_RawMouse_Event
lea gb_rawm(gbl),a0
move.b #IECLASS_RAWMOUSE,ie_Class(a0) ; build rawmouse event
move.w d0,ie_Code(a0)
clr.w ie_X(a0)
clr.w ie_Y(a0)
ire010 clr.b ie_SubClass(a0)
clr.w ie_Qualifier(a0)
move.l ie_NextEvent(a1),ie_NextEvent(a0) ; chain to original event
move.l a0,ie_NextEvent(a1)
rts ; return to caller
*******************************************************************************
* *
* Build_PointerPos_Event *
* *
* This routine creates pointer position event(s) and attaches them to *
* the input event provided. The resolution of the current screen is *
* taken into account when generating the events. The coordinates of the *
* pointer position events are alway represented in the highest *
* resolution i.e. 640x400. The coordinate fields of menus, menu items, *
* etc. are represented in the resolution of the screen to which the *
* menu is attached. When we position the pointer on anything but a *
* hires interlace screen, we must adjust the coordinates that are taken *
* from the menus to allow for this. *
* *
* Input Registers: *
* a0 - address of input event to be built *
* a1 - original input event *
* d0 - number of input events to generate. *
* *
* Output Registers: *
* none. *
* *
*******************************************************************************
Build_PointerPos_Event
iheight equr d1
iwidth equr d1
itopedge equr d2
ileftedge equr d2
mheight equr d3
mwidth equr d3
mtopedge equr d4
mleftedge equr d4
offsetx equr d5
offsety equr d6
movem.l bperegs,-(sp) ; save registers
jsr Insert_PointerPos_Event ; go insert new event
move.l gb_window(gbl),a2 ; get current window
move.l wd_WScreen(a2),a2 ; get window's screen
move.l gb_currentmenu(gbl),a3 ; get current menu
clr.w mtopedge ; force menu's topedge to zero
btst.b #FLAGB_Release2,gb_flags2(gbl) ; release 2.0 ?
bne bpe003 ; yes, branch
add.w sc_ViewPort+vp_DyOffset(a2),mtopedge ; add screen's offset
bpe003 swap mtopedge
move.w mu_LeftEdge(a3),mleftedge ; get menu's leftedge
btst.b #FLAGB_Release2,gb_flags2(gbl) ; release 2.0 ?
bne bpe006 ; yes, branch
add.w sc_ViewPort+vp_DxOffset(a2),mleftedge ; add screen's offset
bpe006 clr.l mheight
move.b sc_BarHeight(a2),mheight ; get menu's height
swap mheight
move.w mu_Width(a3),mwidth ; get menu's width
move.l gb_currentitem(gbl),a3 ; get current menuitem
move.w mi_TopEdge(a3),itopedge ; get menuitem's topedge
swap itopedge
move.w mi_LeftEdge(a3),ileftedge ; get menuitem's leftedge
move.w mi_Height(a3),iheight ; get menuitem's height
swap iheight
move.w mi_Width(a3),iwidth ; get menuitem's width
move.l gb_currentsubitem(gbl),a5 ; is there a subitem ?
move.l a5,d5 ; set cc
beq bpe010 ; no, branch
add.w mi_LeftEdge(a5),ileftedge ; yes, add subitem's leftedge
move.w mi_Width(a5),iwidth ; use subitem's width
swap ileftedge
add.w mi_TopEdge(a5),itopedge ; add subitem's topedge
swap itopedge
swap iwidth
move.w mi_Height(a5),iheight ; use subitem's height
swap iheight
bra bpe025
bpe010 move.l mi_SubItem(a3),a5 ; is there a subitem for this item ?
move.l a5,d5 ; set cc
beq bpe025 ; no, branch
movem.l d0/a0,-(sp) ; save our registers
move.l a5,a0 ; setup subitem for Select_Item
clr.w d5
cmp.w mi_LeftEdge(a5),d5 ; is subitem rendered on item's left ?
ble bpe020 ; no, branch
move.l #s_rightmost,d0 ; set select type
jsr Select_Item
move.l d0,a5 ; get selected item
move.w mi_LeftEdge(a5),d0
add.w mi_Width(a5),d0
add.w d0,ileftedge ; adjust item's leftedge & width
sub.w d0,iwidth
bra bpe023
bpe020 move.l #s_adjacent_top,d0 ; set select type
jsr Select_Item
move.l d0,a5 ; get selected item
move.w mi_LeftEdge(a5),iwidth
sub.w #1,iwidth
bpe023 movem.l (sp)+,d0/a0 ; restore our registers
bpe025 btst.b #FLAGB_Release2,gb_flags2(gbl) ; Release 2.0 ?
beq bpe027 ; no, branch
sub.l #ie_X-iepp_PositionX,a0 ; adjust coordinates address
bra bpe035
bpe027 move.w sc_ViewPort+vp_Modes(a2),d5 ; get screen modes
btst.l #V_HIRES_B,d5 ; is this a hires screen ?
bne bpe030 ; yes, branch
asl.w #1,iwidth ; no, adjust coordinates for hires
asl.w #1,ileftedge
asl.w #1,mwidth
asl.w #1,mleftedge
bpe030 btst.l #V_LACE_B,d5 ; is this an interlace screen ?
bne bpe035 ; yes, branch
swap iwidth ; no, adjust coordinates for interlace
swap ileftedge
swap mwidth
swap mleftedge
asl.w #1,iheight
asl.w #1,itopedge
asl.w #1,mheight
asl.w #1,mtopedge
swap iheight
swap itopedge
swap mheight
swap mtopedge
bpe035 move.l gb_IBase(gbl),a5 ; get intuition base
addq.w #1,mleftedge
move.w mleftedge,offsetx ; get menu leftedge
move.w offsetx,ie_X(a0) ; update event's X coordinate
swap mleftedge
addq.w #1,mtopedge
move.w mtopedge,offsety ; get menu topedge
move.w offsety,ie_Y(a0) ; update event's Y coordinate
asr.w #1,mwidth ; divide menu width by 2
move.w ileftedge,offsetx ; get item leftedge
asr.w #1,iwidth ; divide item width by 2
add.w iwidth,offsetx ; add it to offsetx
swap mwidth
move.w mheight,offsety ; get menu height
asr.w #1,mheight ; divide menu height by 2
swap mheight
swap ileftedge
add.w itopedge,offsety ; add item topedge
swap iwidth
asr #1,iheight ; divide item height by 2
add.w iheight,offsety ; add to offsety
cmp.w #1,d0 ; one event to be generated ?
bne bpe040 ; no, branch
add.w offsetx,ie_X(a0) ; adjust mouse x coordinate
add.w offsety,ie_Y(a0) ; adjust mouse y coordinate
bra bpe045
bpe040 cmp.w #3,d0 ; go to saved mouse position ?
bne bpe042 ; no, branch
move.w gb_old_MouseX(gbl),offsetx
move.w gb_old_MouseY(gbl),offsety
bra bpe044
bpe042 add.w ie_X(a0),offsetx
add.w ie_Y(a0),offsety
bpe044 add.w mwidth,ie_X(a0) ; add menu width to current item
swap mwidth
add.w mheight,ie_Y(a0) ; add menu height to current item
lea gb_ppos2(gbl),a1
lea gb_pp1(gbl),a0 ; setup for release 2.0 just in case
move.l a0,gb_ppos1+ie_EventAddress(gbl)
lea gb_ppos1(gbl),a0 ; new event area
move.w offsetx,d0
move.w offsety,d1
jsr Insert_PointerPos_Event ; go add the event to the chain
bpe045 bset.b #FLAGB_Events_inserted,gb_flags(gbl) ; indicate events added
movem.l (sp)+,bperegs
rts ; return to caller
bperegs reg a0-a5/d1-d6
end